//
// NubbinKnob
//
// Copyright (C) jextra.net.
//
//  This file is part of the net.jextra.crackdep Library.
//
//  The net.jextra.crackdep Library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  The net.jextra.crackdep Library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with the net.jextra.crackdep Library; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
//  02111-1307 USA.
//

package net.jextra.crackdep;

import java.io.*;
import net.jextra.crack.*;
import net.jextra.crack.tool.*;
import net.jextra.crack.type.*;
import net.jextra.dep.*;
import net.jextra.dep.repo.*;

/**
 * <p>
 * These are basic commands for a nubbin "dependency-aware" component.
 * </p>
 */
public class NubbinKnob
{
    // ============================================================
    // Fields
    // ============================================================

    private NubbinKnobParams params;

    // ============================================================
    // Constructors
    // ============================================================

    public NubbinKnob( NubbinKnobParams params )
    {
        this.params = params;
    }

    // ============================================================
    // Methods
    // ============================================================

    // ----------
    // public
    // ----------

    @CrackCommand( description = "Parse the local nubbin files and output the component dependency tree." )
    public void tree()
        throws Exception
    {
        DepTreePrinter printer = new DepTreePrinter();
        printer.print( params.getDepTree(), System.out );
    }

    @CrackCommand( description = "Same as 'tree' command except shows all jars." )
    public void treeVerbose()
        throws Exception
    {
        DepTreePrinter printer = new DepTreePrinter();
        printer.setShowMissingComponents( true );
        printer.print( params.getDepTree(), System.out );
    }

    @CrackCommand( visible = false,
        description = "Output the component dependency tree as if using external store as local repo." )
    public void treeTeam()
        throws Exception
    {
        DepTreePrinter printer = new DepTreePrinter();
        printer.print( params.getTeamDepTree(), System.out );
    }

    @CrackCommand( description = "Parse the depDef file and output the dependency classpath." )
    public void classpath()
        throws Exception
    {
        System.out.println( params.getClasspath() );
    }

    @CrackCommand( description = "Get any components needed from the team-repos and copy them to the local-repo." )
    public void update()
        throws Exception
    {
        DepTreeSearcher searcher = new DepTreeSearcher( params.getTeamDepTree() );

        int numAcquired = 0;
        for ( DepComponentFile entry : searcher.getFiles() )
        {
            // Copy actual file.
            if ( copyFileToLocalRepo( entry ) )
            {
                numAcquired++;
            }
        }

        if ( numAcquired > 0 )
        {
            System.out.printf( "\n%d files have been acquired.\n", numAcquired );
        }
        else
        {
            System.out.println( "\nEverything is already up-to-date.\n" );
        }
    }

    @CrackCommand( description = "Copy build to local-store." )
    public void release()
        throws Exception
    {
        assert params.getBuildDir() != null : "getBuildDir can not be null.";
        assert params.getLocalRepo() != null : "getLocalRepo can not be null.";

        CrackBuild.getInstance().invokeCommand( "build" );

        DepRepoUploader uploader = new DepRepoUploader( params.getLocalRepo() );

        //
        // Copy nubbin file.
        //
        File nubbinFile = params.getSelfNubbinFile();
        uploader.uploadFile( nubbinFile, params.getComponentName(), params.getVersionNumber(),
            "/" + nubbinFile.getName() );

        //
        // Copy all build files
        //
        FileSet fs = new StrainedFileSet( params.getBuildDir() );
        for ( File file : fs )
        {
            uploader.uploadFile( file, params.getComponentName(), params.getVersionNumber(), "/" + file.getName() );
        }
    }

    @CrackCommand( description = "Copy build to given team-store." )
    public void publish( @CrackArg( value = "teamRepo",
        description = "Name of team-repo specified in crack/conf/dep-conf.xml to upload to." ) String teamStore )
        throws Exception
    {
        assert params.getBuildDir() != null : "getBuildDir can not be null.";
        assert teamStore != null : "teamStore arg can not be null.";

        CrackBuild.getInstance().invokeCommand( "build" );

        DepRepoUploader uploader = new DepRepoUploader( params.getTeamRepo( teamStore ) );

        //
        // Copy depDef file.
        //
        File nubbinFile = params.getSelfNubbinFile();
        uploader.uploadFile( nubbinFile, params.getComponentName(), params.getVersionNumber(), nubbinFile.getName() );

        //
        // Copy all build files
        //
        uploader.uploadDir( params.getBuildDir(), params.getComponentName(), params.getVersionNumber(), null );
    }

    // ----------
    // private
    // ----------

    private boolean copyFileToLocalRepo( DepComponentFile entry )
        throws Exception
    {
        if ( entry == null )
        {
            return false;
        }

        File toDir = params.getLocalRepo().getComponentVersionDir( entry.getComponent().getName(),
            entry.getComponent().getVersionNumber() );
        File to = new File( toDir, entry.getName() );

        // If the file already exists, assume that it is up-to-date.
        if ( to.exists() )
        {
            return false;
        }

        to.getParentFile().mkdirs();
        try
        {
            FileCopier copier = new FileCopier();
            copier.copyStream( entry.getInputStream(), to );
        }
        catch ( FileNotFoundException ex )
        {
            System.out.printf( "Source file %s does not exist.\n", entry );
            return false;
        }

        return true;
    }
}
